iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 7
0

本篇的「岔題」在開頭。撰寫鐵人賽系列文章時,我的目標不是完整介紹 Modern C++ 的每一個方面,而是把基本功能與用法,透過簡單的範例,做個粗淺的介紹。C++ 畢竟是資深系統語言,即使範圍限縮在 Modern C++ 完整介紹需要投入相當規模的篇幅。若讀者發現發佈於鐵人賽系列文章只講到皮毛,屬正常現象。

初學 std::shared_ptr<T> 常見幾個疑問:

  • 為什麼需要 std::make_shared?
  • 若函數的參數包含 c<T> ,那麼應該設計成 Call by Value, Call by Reference, Call by Pointer?
  • std::shared_ptr<T> 是不是 thread-safe?

Microsoft 過去一年在 C++ 的文件上做了蠻大幅度的更新,關於 std::shared_ptr 的使用,可以參考這篇文件

為什麼需要 std::make_shared?

「Modern C++」有一個寬鬆的要求:盡可能不要直接使用 new/delete 來建構物件或使用記憶體。遇到 new/delete 應該改用 std::make_unique 或者 std::make_shared 來取代。《Effective Modern C++》Item 21 有說明理由。

第二個理由是為了避免 Memory Leak。考慮以下程式碼:

void Admit1Country2Systems(std::shared_ptr<TeaShopOwner>,
                           bool yes_or_no);

Admit1Country2Systems(std::shared_ptr<TeaShopOwner>(new TeaShopOwner),
                      SayYes());

在 C++17 之前,上述函數呼叫可能出現 Memory Leak,原因是 C++11⁄14 標準規格中,沒有規定函數的參數被處理的順序,因此上述的函數呼叫,有可能發生 new TeaShopOwner 完成,但還沒有被放進 std::shared_ptr 管理,結果 SayYes() 裡拋出異常,因此導致 Memory Leak(new TeaShopOwner 沒有刪除)。

由於以上原因,Modern C++ 最佳實務是「對自己好一點」,盡可能使用 std::make_shared 來創建物件。

函數的參數應該用哪一個型別?

前述例子中的函數將 std::shared_ptr 參數定義為 By Value。「語義」是:呼叫此函數會將傳入的 std::shared_ptr 物件的「參用計數」加一。如此一來,即使呼叫該函數為非同步操作,也不用擔心 std::shared_ptr 管理的物件被提前刪除。

void Admit1Country2Systems(std::shared_ptr<TeaShopOwner>,
                           bool yes_or_no);

關於這個問題,多年前多位 C++ 大神曾經回答過,有興趣的讀者可以觀看這支影片

在場的幾位重量級大神(包含 C++ 之父)針對這個問題也有不同的意見。就現場激起的討論中,我們得到一個結論:C++ 真是一個複雜的程式語言吶。

延伸閱讀


上一篇
DAY 5:Smart Pointer std::shared_ptr<T>,卷一
下一篇
DAY 7:Modern C++ 要角,老語言回春的關鍵,談 auto/decltype,卷一
系列文
山姆大叔談 C++:從歷史談起,再給個定義—Modern C++ 解惑26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
chchwy
iT邦新手 4 級 ‧ 2019-09-19 08:43:32

看了好幾次才看懂這句話的意思:「前述例子中的函數將 std::shared_ptr 參數定義為 By Value。「語義」是:呼叫此函數會將傳入的 std::shared_ptr 物件的「參用計數」加一。」

汗顏/images/emoticon/emoticon02.gif。系列文章還有很多待加強之處,還請多包涵。

我要留言

立即登入留言